package sku

import (
	"context"
	"gorm.io/gorm"
	"mall/common/excption"
	constans "mall/services/product/rpc/consts"
	"mall/services/product/rpc/internal/domain/bo"
	"mall/services/product/rpc/internal/mapper"
	"mall/services/product/rpc/internal/mapper/entity"
	"time"

	"mall/services/product/rpc/internal/svc"
	"mall/services/product/rpc/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type ModifySkuLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewModifySkuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ModifySkuLogic {
	return &ModifySkuLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *ModifySkuLogic) ModifySku(in *pb.ModifySkuDTO) (*pb.EmptyObj, error) {
	// 1.check request dto
	skuMapper, checkError := l.checkRequestDTO(in)
	if checkError != nil {
		return nil, checkError
	}
	// 2.builder entity
	skuEntity, stockMapper, stockEntity, builderErr := l.builderModifyEntity(in)
	if builderErr != nil {
		return nil, builderErr
	}
	// 3.save db
	saveErr := l.saveDB(skuMapper, skuEntity, stockMapper, stockEntity)
	if saveErr != nil {
		return nil, saveErr
	}
	// 4.return obj
	return &pb.EmptyObj{}, nil
}

func (l *ModifySkuLogic) saveDB(skuMapper *mapper.SkuMapper, skuEntity *entity.SkuEntity,
	stockMapper *mapper.SkuStockMapper, stockEntity *entity.SkuStockEntity) error {

	return l.svcCtx.DBEngin.Transaction(func(tx *gorm.DB) error {
		// modify sku info
		updateSkuErr := skuMapper.UpdateCtx(l.ctx, tx, skuEntity)
		if updateSkuErr != nil {
			return updateSkuErr
		}
		// modify sku stock info
		updateStockErr := stockMapper.UpdateCtx(l.ctx, tx, stockEntity)
		if updateStockErr != nil {
			return updateStockErr
		}
		return nil
	})
}

func (l *ModifySkuLogic) builderModifyEntity(in *pb.ModifySkuDTO) (*entity.SkuEntity,
	*mapper.SkuStockMapper, *entity.SkuStockEntity, error) {

	// 2.1 builder sku entity
	skuEntity := entity.SkuEntity{}
	skuEntity.SkuId = in.SkuId
	skuEntity.SkuName = in.SkuName
	skuEntity.Attrs = in.Attrs
	skuEntity.PriceFee = in.PriceFee
	skuEntity.MarketPriceFee = in.MarketPriceFee
	skuEntity.Stock = int64(in.Stock)
	skuEntity.PartyCode = in.PartyCode
	skuEntity.ModelId = in.ModelId
	skuEntity.Weight = float64(in.Weight)
	skuEntity.Volume = float64(in.Volume)
	skuEntity.UpdateTime = time.Now()
	// 2.2 builder sku stock entity
	stockMapper := mapper.NewSkuStockMapper()
	skuStockEntity, err := stockMapper.SelectOneCtx(
		l.ctx,
		l.svcCtx.DBEngin,
		bo.SkuStoreBO{SkuId: in.GetSkuId()},
	)
	if err != nil {
		return nil, nil, nil, err
	}
	if skuStockEntity.StockId <= 0 {
		return nil, nil, nil, excption.NewErrCode(constans.SkuStockNoExistErr)
	}
	stockEntity := entity.SkuStockEntity{}
	stockEntity.StockId = skuStockEntity.StockId
	stockEntity.Stock = skuStockEntity.ActualStock
	stockEntity.UpdateTime = time.Now()
	return &skuEntity, stockMapper, &stockEntity, nil
}

func (l *ModifySkuLogic) checkRequestDTO(in *pb.ModifySkuDTO) (*mapper.SkuMapper, error) {
	skuMapper := mapper.NewSkuMapper()
	skuEntity, err := skuMapper.SelectOneCtx(l.ctx, l.svcCtx.DBEngin, bo.SkuBO{
		SkuId: in.SkuId,
	})
	if err != nil {
		return nil, err
	}
	if skuEntity.SkuId == 0 || int(skuEntity.Status) == constans.SpuTakeDown {
		return nil, excption.NewErrCode(constans.SkuIsDeletedError)
	}
	skuBO := bo.SkuBO{SpuId: skuEntity.SpuId, SkuName: in.SkuName, NeStatus: constans.SpuTakeDown}
	selectOneCtx, err := skuMapper.SelectOneCtx(l.ctx, l.svcCtx.DBEngin, skuBO)
	if err != nil {
		return nil, err
	}
	if selectOneCtx.SpuId > 0 && selectOneCtx.SkuId != in.SkuId {
		return nil, excption.NewErrCode(constans.SkuNameRepeatError)
	}
	return skuMapper, nil
}
